package com.onpositive.units;

import java.text.NumberFormat;
import java.util.Locale;

import org.w3c.dom.Element;

import com.onpositive.data.IPropertyConstants;
import com.onpositive.data.units.Unit;
import com.onpositive.data.units.Units; 
import com.onpositive.knowledge.model.values.IHasValue;

public class ParsedDimension extends ParsedScalar{
	
	/**
	 * 
	 */
	private static final long serialVersionUID = -3687512000304624096L;

	public static final String ID = "dimension" ;

	protected final Unit unit;
	private boolean isDetailed = false ;
	
	public ParsedDimension(double value, Unit unit, String comment) {
		super( value, comment );
		this.unit = unit;
	}
	
	public ParsedDimension ( Double lowerBound, Double upperBound, Unit unit, String comment) {
		super( lowerBound, upperBound, comment);
		this.unit = unit;		
	}
	
	public ParsedDimension ( Double lowerBound, Double upperBound, ParsedDimension pd, String comment) {
		super( lowerBound, upperBound, comment);
		this.unit = pd.getUnit().getPrimaryUnit();		
	}
	
	public ParsedDimension( ParsedValue pv, String comment )
	{
		super( pv, comment ) ;		
		ParsedDimension other = (ParsedDimension) pv ;
		this.unit = other.unit ;
	}
	
	public ParsedDimension( Element element )
	{
		super(element) ;
		
		String unitName = element.getAttribute( IPropertyConstants.CHAR_UNIT_LABEL );
		String unitKindName = element.getAttribute( IPropertyConstants.CHAR_UNIT_KIND_LABEL );
		this.unit = Units.getUnitByShortName( unitName, unitKindName ) ;		
	}

	public ParsedDimension(ParsedDimension other, Object value, String comment) {
		super( other, value, comment ) ;
		this.unit = other.unit.getPrimaryUnit() ;		
	}

	@Override
	public Object describer() {
		return unit;
	}

	@Override
	public void writeValue(Element element) {
		super.writeValue(element) ;
		try{
			element.setAttribute( IPropertyConstants.CHAR_UNIT_LABEL,unit.getShortName() );
			element.setAttribute( IPropertyConstants.CHAR_UNIT_KIND_LABEL,unit.getKind().name() );
			
		}catch(Exception e)
		{
			e.printStackTrace() ;
		}
	}
	@Override
	public String getId() {
		return ID;
	}

	public Unit getUnit() {
		return unit;
	}

	@Override
	public String getValueAsString() {
		
		StringBuilder bld = new StringBuilder() ;
		
		if( isRange() ){
			bld.append( NumberFormat.getInstance( Locale.US ).format(lowerBound) ) ;
			bld.append( getDefaultRangeDelimeter() ) ;
		}
		
		bld.append( NumberFormat.getInstance( Locale.US ).format(upperBound_def) ) ;
		bld.append( " " ) ;
		bld.append( unit.getShortName() ) ;
		
		final String result = bld.toString();
		return result ;
	}
	
	@Override
	public Double getLowerBound() {
		return ( unit != null && lowerBound != null ) ? Units.convertToPrimary(lowerBound, unit ) : null ;
	}

	@Override
	public Double getUpperBound() {
		return ( unit != null && upperBound_def != null ) ? Units.convertToPrimary( upperBound_def, unit ) : null ;
	}
	
	public boolean isDetailed() {
		return isDetailed;
	}

	public void setDetailed() {
		this.isDetailed = true ;
	}
	
	public static ParsedDimension appendValue( ParsedDimension val0, ParsedDimension val1, Unit baseUnit, Object modifier)
	{
		Unit unit0 = val0.getUnit() ;
		Unit unit1 = val0.getUnit() ;
		
		double newValue ;
		if( unit0 == baseUnit )
		{
			double rel = val1.getUnit().getRelationToPrimary() / baseUnit.getRelationToPrimary() ;
			newValue = val0.upperBound_def + val1.upperBound_def * rel ;
		}
		else if( unit1 == baseUnit )
		{
			double rel = val0.getUnit().getRelationToPrimary() / baseUnit.getRelationToPrimary() ;
			newValue = val0.upperBound_def + val1.upperBound_def * rel ;			
		}
		else{
			double rel0 = val1.getUnit().getRelationToPrimary() / baseUnit.getRelationToPrimary() ;
			double rel1 = val0.getUnit().getRelationToPrimary() / baseUnit.getRelationToPrimary() ;
			newValue = val0.upperBound_def * rel1 + val1.upperBound_def * rel0 ;			
		}
		
		StringBuilder bld = new StringBuilder( modifier.getClass().getSimpleName() ) ;
		bld.append(" val append. old:") ;
		bld.append( val1.getComment() ) ;
		bld.append( ", new:" ) ;
		bld.append( val0.getComment() );
		String comment = bld.toString() ;
		
		ParsedDimension finalVal = new ParsedDimension(newValue, baseUnit, comment) ;
		finalVal.setDetailed() ;
		return finalVal ;
	
	}
	
	@Override
	public IHasValue clone(Object value, String comment) {
		
		if( comment == null )
			comment = this.getComment() ;
		
		if( value instanceof Double[] || value instanceof Double )
			return new ParsedDimension( this, value, comment );
		
		if(! (value instanceof double[]) )
			return null;
		
		double[] srcArr = (double[]) value ;
		int l = srcArr.length ;
		Double[] valArr = new Double[l] ;
		for( int i = 0 ; i < l ; i++ )
			valArr[i] = srcArr[i] ;
		
		return new ParsedDimension( this, value, comment );		
	}

	@Override
	public int hashCode() {
		final int prime = 31;
		int result = super.hashCode();
		result = prime * result + (isDetailed ? 1231 : 1237);
		result = prime * result + ((unit == null) ? 0 : unit.hashCode());
		return result;
	}

	@Override
	public boolean equals(Object obj) {
		if (this == obj)
			return true;
		if (!super.equals(obj))
			return false;
		if (getClass() != obj.getClass())
			return false;
		ParsedDimension other = (ParsedDimension) obj;
		if (isDetailed != other.isDetailed)
			return false;
		if (unit == null) {
			if (other.unit != null)
				return false;
		} else if (!unit.equals(other.unit))
			return false;
		return true;
	}
	
}
